package top.tangyh.lamp.care.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.tangyh.basic.cache.redis2.RedisOps;
import top.tangyh.basic.exception.BizException;
import top.tangyh.lamp.care.common.ObsrvCfgValUnil;
import top.tangyh.lamp.care.common.ObsvCfgDataTypeEnum;
import top.tangyh.lamp.care.common.ReflectionUtils;
import top.tangyh.lamp.care.entity.BObsvCfgDetail;
import top.tangyh.lamp.care.entity.BObsvPtCfg;
import top.tangyh.lamp.care.mapper.BObsvCfgDetailMapper;
import top.tangyh.lamp.care.mapper.BObsvCfgMapper;
import top.tangyh.lamp.care.mapper.BObsvPtCfgMapper;
import top.tangyh.lamp.care.service.BObsvCfgDetailService;
import top.tangyh.lamp.care.service.BObsvCfgService;
import top.tangyh.basic.base.service.impl.SuperServiceImpl;
import top.tangyh.lamp.care.manager.BObsvCfgManager;
import top.tangyh.lamp.care.entity.BObsvCfg;
import top.tangyh.lamp.care.vo.query.ObsvCfgQueryParam;
import top.tangyh.lamp.care.vo.result.*;
import top.tangyh.lamp.care.vo.save.BObsvCfgSaveVO;
import top.tangyh.lamp.care.vo.update.BObsvCfgUpdateVO;
import top.tangyh.lamp.care.vo.query.BObsvCfgPageQuery;
import top.tangyh.lamp.common.constant.CommonConstant;
import top.tangyh.lamp.common.constant.ObsvConstant;
import top.tangyh.lamp.common.utils.ConfDataModelUtil;
import top.tangyh.lamp.common.utils.ConvertUtil;
import top.tangyh.lamp.system.service.system.DefDictItemService;
import top.tangyh.lamp.system.vo.result.system.DefDictItemResultVO;

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import static top.tangyh.lamp.common.constant.CommonConstant.BIND_EQU_PATIENT;

/**
 * <p>
 * 业务实现类
 * 观察项配置主表
 * </p>
 *
 * @author zqb
 * @date 2024-07-26 11:20:21
 * @create [2024-07-26 11:20:21] [zqb] [代码生成器生成]
 */
@Slf4j
@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class BObsvCfgServiceImpl extends SuperServiceImpl<BObsvCfgManager, Long, BObsvCfg> implements BObsvCfgService {

    /**
     * 观察项类型字段名
     */
    private final static String OBSV_TYPE = "obsvType";
    /**
     * 字段名为：dataDefine
     */
    private final static String FIELD_Name_DATA_DEFINE = "dataDefine";
    /**
     * 查询返回字明细字段名
     */
    private final static String DETAIL = "detail";

    private final BObsvCfgMapper bObsvCfgMapper;

    private final BObsvPtCfgMapper bObsvPtCfgMapper;

    private final BObsvCfgDetailMapper bObsvCfgDetailMapper;

    private final DefDictItemService defDictItemService;


    private final BObsvCfgDetailService bObsvCfgDetailService;

    private final RedisOps redisOps;

    /**
     * 查询观察项全局配置，该配置适用于观察记录查询所需全局配置，返回是分类处理的 观察项配置集合
     *
     * @param param 观察项配置全局查询参数
     * @return
     */
    @Override
    public List<ObsvCfgForRdDto> queryForRd(ObsvCfgQueryParam param) {
        LambdaQueryWrapper<BObsvCfg> queryWrapper = newQueryWrapper(param);
        List<ObsvCfgDto> list = bObsvCfgMapper.findListForRd(null, null, queryWrapper);
        List<ObsvCfgForRdDto> rst = ConfDataModelUtil.classify(list, Stream.of(OBSV_TYPE).collect(Collectors.toList()), DETAIL, ObsvCfgForRdDto.class, ObsvCfgDto.class);



        if (rst == null || rst.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, DefDictItemResultVO> obsvTypes = defDictItemService.getDictDetailsByParentKey(ObsvConstant.DICT_KEY_OBSV_TYPE);

//        Map<String, DefDictItemResultVO> obsvTypes = new HashMap<>();

        // 假设添加了一些DefDictItemResultVO对象到obsvTypes中

        // 对Map中的条目按sortValue字段进行排序
//        Map<String, DefDictItemResultVO> sortedMap = obsvTypes.entrySet().stream()
//                .sorted(Map.Entry.comparingByValue(Comparator.comparingInt(DefDictItemResultVO::getSortValue)))
//                .collect(Collectors.toMap(
//                        Map.Entry::getKey,
//                        Map.Entry::getValue,
//                        (e1, e2) -> e1, // 如果有重复的key, 选择第一个
//                        LinkedHashMap::new // 保持插入顺序
//                ));


        //枚举配置缓存，key观察项标识
        Map<String, ObsvCfgDto> cacheEnumMap = getAllEnum(true);
        rst = rst.stream().filter(item -> item != null).map(item -> {
            DefDictItemResultVO dictDetail = obsvTypes.get(item.getObsvType());
            if (dictDetail != null && StrUtil.isNotBlank(dictDetail.getName())) {
                item.setObsvTypeName(dictDetail.getName());
                item.setSortValue(dictDetail.getSortValue());
            }

            if (item.getDetail() != null) {
                //填充dataDefine
                fillDataDefine(cacheEnumMap, item.getDetail());
                for (ObsvCfgDto cfg : item.getDetail()) {
                    if (!ObsvConstant.COMPLEX_TYPE.contains(cfg.getDataType())) {
                        cfg.setDetail(null);
                    }
                }
            }

            return item;
        }).collect(Collectors.toList());

        // 根据sortValue字段排序
        rst = rst.stream()
                .sorted(Comparator.comparingInt(ObsvCfgForRdDto::getSortValue))
                .collect(Collectors.toList());

        return rst;

    }

    @Override
    public void fillDataDefine(List<ObsvCfgDto> list, boolean isAll) {
        if (CollectionUtil.isEmpty(list)) {
            return;
        }
        Map<String, ObsvCfgDto> cacheMap = getAllEnum(isAll);
        //没有枚举基本配置不需要处理
        if (CollectionUtil.isEmpty(cacheMap)) {
            return;
        }

        fillDataDefine(cacheMap, list);
    }

    /**
     * 对结构体中的枚举填充dataDefine字段
     *
     * @param cacheMap 是key为观察项的标识、Value为枚举定义的缓存集合
     * @param list
     */
    public void fillDataDefine(Map<String, ObsvCfgDto> cacheMap, List<ObsvCfgDto> list) {
        if (CollectionUtil.isEmpty(list) || CollectionUtil.isEmpty(cacheMap)) {
            return;
        }
        //没有枚举基本配置不需要处理
        if (CollectionUtil.isEmpty(cacheMap)) {
            return;
        }

        for (ObsvCfgDto cfg : list) {
            //不是结构体，或没有有明细不需要填充
            if (cfg == null || CollectionUtil.isEmpty(cfg.getDetail()) || !ObsvConstant.TYPE_STRUCT.equals(cfg.getDataType())) {
                continue;
            }
            fillDataDefineByDeetail(cacheMap, cfg.getDetail());
        }
    }

    /**
     * 填充明细记录中数据类型是枚举的dataDefine
     *
     * @param cacheMap 是key为观察项的标识、Value为枚举定义的缓存集合
     * @param list     - 观察项明细记录集
     */
    public void fillDataDefineByDeetail(Map<String, ObsvCfgDto> cacheMap, List<ObsvCfgDetailDto> list)   {
        if (CollectionUtil.isEmpty(list) || CollectionUtil.isEmpty(cacheMap)) {
            return;
        }
        //没有枚举基本配置不需要处理
        if (CollectionUtil.isEmpty(cacheMap)) {
            return;
        }

        for (Object item : list) {
            ObsvCfgDetailDto detail = BeanUtil.toBean(item, ObsvCfgDetailDto.class);
            //仅对子项是枚举的进行填充
            if (detail == null || detail.getDataType() == null || !ObsvConstant.TYPE_ENUM.equals(detail.getDataType())) {
                continue;
            }
            ObsvCfgDto enumCfg = cacheMap.get(detail.getObsvCode());
            List<ObsvCfgDetailDto> enumDetail = enumCfg == null || CollectionUtil.isEmpty(enumCfg.getDetail()) ? new ArrayList<>() : enumCfg.getDetail();
            BeanUtil.setProperty(item, FIELD_Name_DATA_DEFINE, enumDetail);
//            try {
//                BeanUtils.setProperty(item, FIELD_Name_DATA_DEFINE, enumDetail);
//            } catch (IllegalAccessException e) {
//                throw new RuntimeException(e);
//            } catch (InvocationTargetException e) {
//                throw new RuntimeException(e);
//            }
            // 使用示例
//            try {
//                ReflectionUtils.setField(item, "dataDefine", enumDetail);
//            } catch (NoSuchFieldException e) {
//                throw new RuntimeException(e);
//            } catch (IllegalAccessException e) {
//                throw new RuntimeException(e);
//            }
//            ObsvCfgDetailDto detailR = BeanUtil.toBean(item, ObsvCfgDetailDto.class);
//            if(null!=detailR.getDataDefine()){
//                ObjectMapper objectMapper = new ObjectMapper();
//                List<ObsvCfgDetailDto> dataDefineList = objectMapper.readValue(detailR.getDataDefine(), new TypeReference<List<ObsvCfgDetailDto>>() {});
//                // 现在你可以使用 dataDefineList 了
//                detailR.setDataDefine(dataDefineList);
//            }

        }
//        for (Object item : list) {
//            ObsvCfgDetailDto obsvCfgDetailDto=BeanUtil.toBean(item, ObsvCfgDetailDto.class);
//
//            if (obsvCfgDetailDto == null || obsvCfgDetailDto.getDataType() == null || !ObsvConstant.TYPE_ENUM.equals(obsvCfgDetailDto.getDataType())) {
//                continue;
//            }
//            ObsvCfgDto enumCfg = cacheMap.get(obsvCfgDetailDto.getObsvCode());
//            List<ObsvCfgDetailDto> enumDetail = enumCfg == null || CollectionUtil.isEmpty(enumCfg.getDetail()) ? new ArrayList<>() : enumCfg.getDetail();
////            BeanUtil.setProperty(obsvCfgDetailDto, FIELD_Name_DATA_DEFINE, enumDetail);
//            if(enumDetail.size()>0){
//                obsvCfgDetailDto.setDataDefine(enumDetail);
//            }
//
//           // BeanUtil.copyToList(obsvCfgDetailDto.getDataDefine(),enumDetail);
//            System.out.println(obsvCfgDetailDto.getDataDefine());
//            item=obsvCfgDetailDto;
//            System.out.println(item);
//        }

    }

    @Override
    public Map<String, ObsvCfgDto> getAllEnum(boolean isAll) {
        LambdaQueryWrapper<BObsvCfg> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BObsvCfg::getIsDeleted, CommonConstant.NO_NUMBER)
                .eq(BObsvCfg::getDataType, ObsvConstant.TYPE_ENUM);
        if (!isAll) {
            queryWrapper.eq(BObsvCfg::getIsVisible, CommonConstant.YES_NUMBER)
                    .eq(BObsvCfg::getIsEnable, CommonConstant.YES_NUMBER);
        }
        List<BObsvCfg> yxObsvCfgs = bObsvCfgMapper.selectList(queryWrapper);
        //填充明细值
        List<ObsvCfgDto> obsvCfgDtos = fillDetail(yxObsvCfgs);
        if (CollectionUtil.isEmpty(obsvCfgDtos)) {
            return new HashMap<>(1);
        }

        Map<String, ObsvCfgDto> rst = obsvCfgDtos.stream().collect(Collectors.toMap(ObsvCfgDto::getObsvCode, o -> o, (k1, k2) -> k1));
        return rst;
    }

    /**
     * 填充明细值
     *
     * @param yxObsvCfgs 需填充参数
     * @return
     */
    private List<ObsvCfgDto> fillDetail(List<BObsvCfg> yxObsvCfgs) {
        List<ObsvCfgDto> obsvCfgDtos = ConvertUtil.convertList(yxObsvCfgs, ObsvCfgDto.class);
        obsvCfgDtos = obsvCfgDtos.stream().map(obsv -> {
            if (ObsvConstant.TYPE_STRUCT.equals(obsv.getDataType()) || ObsvConstant.TYPE_ENUM.equals(obsv.getDataType())) {
                List<ObsvCfgDetailDto> obsvCfgDetailDtos = bObsvCfgDetailService.selectByCfgId(obsv.getId());
                obsv.setDetail(obsvCfgDetailDtos);
            }
            return obsv;
        }).collect(Collectors.toList());
        return obsvCfgDtos;
    }

    private LambdaQueryWrapper<BObsvCfg> newQueryWrapper(ObsvCfgQueryParam param) {
        LambdaQueryWrapper<BObsvCfg> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BObsvCfg::getIsDeleted, CommonConstant.NO_NUMBER);
        if (param == null) {
            return queryWrapper;
        }
        queryWrapper.eq(param.getId() != null, BObsvCfg::getId, param.getId())
                .like(StrUtil.isNotBlank(param.getObsvCode()), BObsvCfg::getObsvCode, param.getObsvCode())
                .like(StrUtil.isNotBlank(param.getObsvName()), BObsvCfg::getObsvName, param.getObsvName())
                .eq(StrUtil.isNotBlank(param.getDataType()), BObsvCfg::getDataType, param.getDataType())
                .eq(StrUtil.isNotBlank(param.getObsvType()), BObsvCfg::getObsvType, param.getObsvType())
                .eq(param.getIsEnable() != null, BObsvCfg::getIsEnable, param.getIsEnable())
                .eq(param.getIsVisible() != null, BObsvCfg::getIsVisible, param.getIsVisible())
                .eq(param.getIsDev() != null, BObsvCfg::getIsDev, param.getIsDev());

        return queryWrapper;
    }


    @Override
    public PageOutputDTO<ObsvCfgDto> queryPage(ObsvCfgQueryParam param) {
        LambdaQueryWrapper<BObsvCfg> queryWrapper = newQueryWrapper(param);

        if (StrUtil.isNotBlank(param.getNotDataTypes())) {
            List<String> notDataTypeList = Stream.of(param.getNotDataTypes().split(",")).collect(Collectors.toList());
            queryWrapper.notIn(BObsvCfg::getDataType, notDataTypeList);
        }

        Integer limitStart = param.getPage() == null || param.getSize() == null ? null : (param.getPage() - 1) * param.getSize();


        List<ObsvCfgDto> list = bObsvCfgMapper.findList(limitStart, param.getSize(), queryWrapper);

        list = list.stream().map(o -> ObsrvCfgValUnil.doCfgVal(o)).collect(Collectors.toList());
        //填充结构体的子项的枚举定义
        fillDataDefine(list, true);
        PageOutputDTO<ObsvCfgDto> rst = new PageOutputDTO<>();
        rst.setList(list);
        rst.setCurrent(Convert.toLong(param.getPage()));
        rst.setPage(Convert.toLong(param.getSize()));
        long total = bObsvCfgMapper.findListCount(queryWrapper);
        rst.setTotal(total);
        return rst;
    }


    /**
     * 参数检验
     */
    private void validParam(ObsvCfgDto param) {
        if (!ObsvCfgDataTypeEnum.getAllCode().contains(param.getDataType())) {
            throw new BizException("数据类型不存在");
        }
        //标识在数据库中是否重复
        QueryWrapper<BObsvCfg> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(BObsvCfg::getIsDeleted, CommonConstant.NO_NUMBER)
                .eq(BObsvCfg::getObsvCode, param.getObsvCode());
        if (param.getId() != null) {
            queryWrapper.lambda().ne(BObsvCfg::getId, param.getId());
        }
        List<BObsvCfg> cfgListDb = bObsvCfgMapper.selectList(queryWrapper);
        if (cfgListDb.size() > 0) {
            throw new BizException("标识" + param.getObsvCode() + "重复");
        }


        if (param.getDetail() == null || param.getDetail().isEmpty()) {
            return;
        }
        //对结构明细中标识检查
        Set<String> codeSet = new HashSet<>();
        for (ObsvCfgDetailDto item : param.getDetail()) {
            if (codeSet.contains(item.getObsvCode())) {
                throw new BizException(param.getObsvCode() + "下的标识重复(" + item.getObsvCode() + ")");
            }
            codeSet.add(item.getObsvCode());
        }
    }

    /**
     * 新增或保存所有观察项数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ObsvCfgDto insertOrUpdate(ObsvCfgDto param) {
        //参数检验
        validParam(param);

        //观察项配置主表处理
        Long id = param.getId();
        BObsvCfg yxObsvCfg = BeanUtil.copyProperties(param, BObsvCfg.class);

        if (id != null) {
            //观察项标识不能修改
            yxObsvCfg.setObsvCode(null);
            LambdaUpdateWrapper<BObsvCfg> updateWrapper = new LambdaUpdateWrapper<BObsvCfg>();
            updateWrapper.set(BObsvCfg::getRefLower, yxObsvCfg.getRefLower());
            updateWrapper.set(BObsvCfg::getRefUpper, yxObsvCfg.getRefUpper());
            updateWrapper.eq(BObsvCfg::getId, yxObsvCfg.getId());
            bObsvCfgMapper.update(yxObsvCfg, updateWrapper);
            //同步观察明细，当结构体的子项变动时，含有该项的所有结构的子项都同步
            List<BObsvCfgDetail> detaiListDb = bObsvCfgDetailService.findByObsvCfgId(id);
            List<Long> needUpdateDetail = detaiListDb.stream().map(o -> o.getId()).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(needUpdateDetail)) {
                BObsvCfgDetail detial1 = new BObsvCfgDetail();
                detial1.setObsvName(yxObsvCfg.getObsvName());
                detial1.setPropUnit(yxObsvCfg.getPropUnit());
                detial1.setRefLower(yxObsvCfg.getRefLower());
                detial1.setRefUpper(yxObsvCfg.getRefUpper());
                detial1.setIsEnable(yxObsvCfg.getIsEnable());
                detial1.setIsVisible(yxObsvCfg.getIsVisible());
                detial1.setDefaultValue(yxObsvCfg.getDefaultValue());
                LambdaUpdateWrapper<BObsvCfgDetail> detailUpdateWrapper = new LambdaUpdateWrapper<>();
                detailUpdateWrapper.set(BObsvCfgDetail::getRefLower, yxObsvCfg.getRefLower());
                detailUpdateWrapper.set(BObsvCfgDetail::getRefUpper, yxObsvCfg.getRefUpper());
                detailUpdateWrapper.in(BObsvCfgDetail::getId, needUpdateDetail);
                bObsvCfgDetailMapper.update(detial1, detailUpdateWrapper);
            }

        } else {
            bObsvCfgMapper.insert(yxObsvCfg);
            id = yxObsvCfg.getId();
            yxObsvCfg.setId(id);
            param.setId(id);

            //保存 code和id的队友关系 方便 后续取值
            redisOps.set(yxObsvCfg.getObsvCode(), yxObsvCfg.getId());
        }

        //保存观察项配置明细
        if (CollectionUtil.isNotEmpty(param.getDetail())) {
            //找出所有数据库子项
            Map<Long, BObsvCfgDetail> detailMap = bObsvCfgDetailService.findChilrdernWithMap(id);

            log.debug("-----------观察项明细保存-----{}", JSON.toJSONString(BeanUtil.getProperty(param, "detail"), true));
            //先删除
            bObsvCfgDetailService.delChildren(id);
            //从表在参数检验函数中 已经对用户输入的从表的业务主键进行了重复性检测
            for (ObsvCfgDetailDto item : param.getDetail()) {
                BObsvCfgDetail dt = BeanUtil.copyProperties(item, BObsvCfgDetail.class);
                //处理观察项默认值
                doEnumDefaultOfDetailBySave(dt);
                //所有子项的标识不能被修改
                if (CollectionUtil.isNotEmpty(detailMap) && detailMap.containsKey(item.getId())) {
                    BObsvCfgDetail detalTmp = detailMap.get(item.getId());
                    if (detalTmp != null) {
                        dt.setObsvCode(detalTmp.getObsvCode());
                    }
                }
                dt.setSortTime((new Date()).getTime());
                dt.setIsDeleted(CommonConstant.NO_NUMBER);
                dt.setObsvCfgId(id);
                //让表自动生成主键
                dt.setId(null);
                bObsvCfgDetailMapper.insert(dt);
                item.setId(dt.getId());
            }
        }

        //同步病人观察项配置
        LambdaQueryWrapper<BObsvPtCfg> yxObsvPtCfgWrapper = new LambdaQueryWrapper<>();
        yxObsvPtCfgWrapper.eq(BObsvPtCfg::getObsvId, id)
                .eq(BObsvPtCfg::getIsDeleted, CommonConstant.NO_NUMBER);
        BObsvPtCfg yxObsvPtCfg = new BObsvPtCfg();
        yxObsvPtCfg.setObsvCode(param.getObsvCode());
        yxObsvPtCfg.setObsvType(param.getObsvType());
        yxObsvPtCfg.setPropUnit(param.getPropUnit());
        bObsvPtCfgMapper.update(yxObsvPtCfg, yxObsvPtCfgWrapper);
        return param;
    }

    /**
     * 处理结构体中明细的枚举默认值
     *
     * @param dt 明细
     */
    private void doEnumDefaultOfDetailBySave(BObsvCfgDetail dt) {
        if (dt == null || StrUtil.isBlank(dt.getDataType()) || !ObsvConstant.TYPE_ENUM.equals(dt.getDataType())) {
            return;
        }
        BObsvCfg yxObsvCfg = bObsvCfgMapper.findByCode(dt.getObsvCode());
        dt.setDefaultValue(yxObsvCfg.getDefaultValue());
    }


    @Override
    public List<BObsvCfg> getObsvCfgByParam(Set<String> obsvcodes) {
        return bObsvCfgMapper.getObsvCfgByParam(obsvcodes);
    }

    /**
     * 根据观察项Code获得未删除的配置
     *
     * @param itemCode 观察项code
     * @return
     */
    @Override
    public   List<BObsvCfg> getByCodeAndNoDel(String itemCode) {
        if (StrUtil.isBlank(itemCode)) {
            return null;
        }
        LambdaQueryWrapper<BObsvCfg> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BObsvCfg::getIsDeleted, CommonConstant.NO_NUMBER);
        wrapper.eq(BObsvCfg::getObsvCode, itemCode);
        List<BObsvCfg> rst = bObsvCfgMapper.selectList(wrapper);
        return rst;
    }

    @Override
    public BObsvCfg getOneByCodeAndNoDel(String itemCode) {
        List<BObsvCfg> list = getByCodeAndNoDel(itemCode);
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

}


